import { AppTask } from "../../app.task.class";
import { V3proScreenAllStatus } from "../../../api/v3pro-api/v3pro.api.response.model";
import { loggerStdout } from "../../../configs/log.config";
import { V3proSubjectMessage } from "../../v3pro-task/model/v3pro.model";
import fs from "node:fs";
import { getAppDataPath } from "../../../utils/app.util";
import { HealthCheckTask } from "../../v3pro-task/health-check/health.check.class";
import { Subject } from "rxjs";
import { V3proCheckSendboxSignalInputTask } from "../../v3pro-task/health-check/v3pro.check.sendbox.signal.input.task";
import {
  v3proMockScreenAllStatus,
  v3proMockScreenAllStatusWithBadPixel,
} from "../../v3pro-task/util/v3pro.mock";
import {
  HealthDescEnum,
  HealthEnum,
  V3proPanelStatusEnum,
} from "../../v3pro-task/model/v3pro.enum";
import { V3ProBinaryPixel } from "../../v3pro-task/util/v3pro.binary.pixel";
import { V3proScreenLayoutHelper } from "../../v3pro-task/helper/v3pro.screen.layout.helper";
import { V3proScreenImageHelper } from "../../v3pro-task/helper/v3pro.screen.image.helper";
import { createTimestampFilename } from "../../../utils/file.util";
import { V3proCheckPanelSignalTask } from "../../v3pro-task/health-check/v3pro.check.panel.signal.task";
import { V3proCheckTemperatureTask } from "../../v3pro-task/health-check/v3pro.check.temperature.task";
import { V3proCheckScanboardErrorRestartTask } from "../../v3pro-task/health-check/v3pro.check.scanboard.error.restart.task";
import { sleep } from "../../../utils/cmm.util";
import { V3proAllStatusLambda } from "../../v3pro-task/helper/v3pro.all.status.lambda.helper";
import { V3proCheckPanelTemperatureTask } from "../../v3pro-task/health-check/v3pro.check.panel.temperature.task";
import { V3proCheckPanelVoltageTask } from "../../v3pro-task/health-check/v3pro.check.panel.voltage.task";
import { SRFileTypeEnum } from "../../starriver-task/model/sr.enum";
import { SRSendBoxFile } from "../../v3pro-task/model/v3pro.file.model";
import { V3proCheckSendboxNetworkLinkTask } from "../../v3pro-task/health-check/v3pro.check.sendbox.network.link.task";
import { V3proCheckSendboxDoorTask } from "../../v3pro-task/health-check/v3pro.check.sendbox.door.task";
import { V3proCheckDeadPixelTask } from "../../v3pro-task/health-check/v3pro.check.dead.pixel.task";

const saveMessages = (message: V3proSubjectMessage, dir: string, messageName = "message") => {
  const p = `health-test/${dir}/${messageName}`;
  message.files?.forEach((file) => {
    fs.cpSync(file.file.name, getAppDataPath(p, file.fileName));
  });
  fs.writeFileSync(getAppDataPath(p, "message.json"), JSON.stringify(message, null, 2));
};

const save = (dir: string, content: any) => {
  const p = `health-test/test/`;
  fs.writeFileSync(getAppDataPath(p, "message.json"), JSON.stringify(content, null, 2));
};

const subjectMessage = (task: HealthCheckTask, messageCount = 1) => {
  return new Promise((resolve, reject) => {
    const subject = new Subject<V3proSubjectMessage>();
    let count = 0;
    let timer = setTimeout(() => {
      reject("timeout");
      task.stop().then();
    }, 10_000);
    subject.subscribe((message) => {
      loggerStdout.info(
        "message-result: %s [count] %s [image] %s [json] %s",
        !message.isErrStatus(),
        count,
        message.files
          ?.filter((f) => f.type === SRFileTypeEnum.SCREEN_IMAGE)
          .map((x) => x.fileName)
          .join(","),
        message.files
          ?.filter((f) => f.type === SRFileTypeEnum.SCREEN_ERROR)
          .map((x) => x.fileName)
          .join(","),
      );
      saveMessages(message, message.alertType as string, "message" + count++);
      if (count === messageCount) {
        clearTimeout(timer);
        resolve(true);
      }
    });
    task.setObservable(subject).start().then();
  });
};
/**
 * 注册屏幕
 */
export class CmdHealthTestHandler extends AppTask {
  __pause(): Promise<boolean> {
    return Promise.resolve(false);
  }

  __restore(): Promise<boolean> {
    return Promise.resolve(false);
  }

  async __run(): Promise<void> {
    loggerStdout.info("test start");
    // await this.testDrawImage();
    // await this.test4KDrawImage();
    // await this.testPanelSignInput();
    // await this.testSendBoxSignalInput();
    // await this.testTemp();
    // await this.testScanBoardErrRestart();
    // await this.testPanelTemp();

    // await this.testPanelVoltage();
    // await this.testLayoutExport();
    // await this.testSendBoxNetWorkErr();
    // await this.testOpenDoorErr();
    await this.testBadPixel();

    loggerStdout.info("test finish");
  }

  async testBadPixel() {
    const allStatus = v3proMockScreenAllStatusWithBadPixel();
    await subjectMessage(new V3proCheckDeadPixelTask(allStatus));
  }

  async testOpenDoorErr() {
    const allStatus = v3proMockScreenAllStatus();
    const helper = new V3proScreenLayoutHelper(allStatus);
    allStatus.sendBoxs[0].status.ioInputArr[0].status = "on";
    allStatus.sendBoxs[3].status.ioInputArr[0].status = "on";
    await subjectMessage(new V3proCheckSendboxDoorTask(allStatus));
  }

  /**
   * 绘图
   */
  async testSendBoxNetWorkErr() {
    const allStatus = v3proMockScreenAllStatus();
    const helper = new V3proScreenLayoutHelper(allStatus);
    allStatus.sendBoxs[0].status.healthDesc.description = HealthDescEnum.COMM_NODE_ERR;
    allStatus.sendBoxs[0].status.communication.interfacesSta[1].healthStatus = "ERROR";
    allStatus.sendBoxs[0].status.communication.interfacesSta[4].healthStatus = "ERROR";
    await subjectMessage(new V3proCheckSendboxNetworkLinkTask(allStatus));
  }

  /**
   * 绘图
   */
  async testLayoutExport() {
    const allStatus = v3proMockScreenAllStatus();
    const helper = new V3proScreenLayoutHelper(allStatus);
    helper.setPanelErrById(allStatus.sendBoxs[0].layout.outPorts[0].scanBoards[0].id, 0);
    helper.setPanelErrById(allStatus.sendBoxs[0].layout.outPorts[3].scanBoards[3].id, 0);
    const json = new SRSendBoxFile([], helper.exportLayout());
    save("layout", json);
  }

  /**
   * 面板电压异常
   */
  async testPanelVoltage() {
    try {
      const allStatus: V3proScreenAllStatus = v3proMockScreenAllStatus();
      allStatus.sendBoxs[1].scanBoards[1].status.panels[1].healthDesc.description = [
        HealthDescEnum.VOLTAGE_HIGH,
      ];
      await subjectMessage(new V3proCheckPanelVoltageTask(allStatus));
    } catch (e: any) {
      loggerStdout.error(e?.message || e);
    }
  }

  /**
   * 面板温度异常
   */
  async testPanelTemp() {
    try {
      const allStatus: V3proScreenAllStatus = v3proMockScreenAllStatus();
      const path = ["healthDesc", "description"];
      [
        [1, 1, 1],
        [2, 2, 2],
      ].forEach((v) => {
        allStatus.sendBoxs[v[0]].scanBoards[v[1]].status.panels[v[2]].healthDesc.description = [
          HealthDescEnum.OVER_TEMP,
        ];
      });
      await subjectMessage(new V3proCheckPanelTemperatureTask(allStatus));

      allStatus.sendBoxs[1].status.communication.control.status = "ERROR";
      await subjectMessage(new V3proCheckPanelTemperatureTask(allStatus));

      allStatus.sendBoxs[1].status.communication.control.status = "OK";
      allStatus.sendBoxs[1].scanBoards[1].status.panels[1].healthDesc.description = [
        HealthDescEnum.NORMAL,
      ];
      await subjectMessage(new V3proCheckPanelTemperatureTask(allStatus));
    } catch (e: any) {
      loggerStdout.error(e?.message || e);
    }
  }

  /**
   * 扫描板异常重启
   */
  async testScanBoardErrRestart() {
    try {
      loggerStdout.info("扫描板异常重启");
      const allStatus: V3proScreenAllStatus = v3proMockScreenAllStatus();
      const {
        status: { runStatus },
      } = allStatus.sendBoxs[0].scanBoards[0];
      runStatus.uptimeS = 100000;
      await subjectMessage(new V3proCheckScanboardErrorRestartTask(allStatus));

      runStatus.uptimeS = 10000;
      await subjectMessage(new V3proCheckScanboardErrorRestartTask(allStatus));

      runStatus.uptimeS = 1000;
      await subjectMessage(new V3proCheckScanboardErrorRestartTask(allStatus));

      runStatus.uptimeS = 10;
      await subjectMessage(new V3proCheckScanboardErrorRestartTask(allStatus));
    } catch (e: any) {
      loggerStdout.error(e?.message || e);
    }
  }

  /**
   * 温度故障
   */
  async testTemp() {
    try {
      loggerStdout.info("温度故障");
      const allStatus: V3proScreenAllStatus = v3proMockScreenAllStatus();
      allStatus.sendBoxs[0].status.runStatus.workingTempC = 100;
      allStatus.sendBoxs[1].scanBoards[2].status.runStatus.workingTempC = 100;

      await subjectMessage(new V3proCheckTemperatureTask(allStatus));
      await sleep(5000);
      await subjectMessage(new V3proCheckTemperatureTask(allStatus));

      await sleep(12000);
      await subjectMessage(new V3proCheckTemperatureTask(allStatus));
      allStatus.sendBoxs[0].status.runStatus.workingTempC = 50;
      allStatus.sendBoxs[1].scanBoards[2].status.runStatus.workingTempC = 50;

      await sleep(5000);
      await subjectMessage(new V3proCheckTemperatureTask(allStatus));
    } catch (e: any) {
      loggerStdout.error(e?.message || e);
    }
  }

  /**
   * 发送盒信号故障
   */
  async testPanelSignInput() {
    try {
      loggerStdout.info("面板信号故障");
      const allStatus: V3proScreenAllStatus = v3proMockScreenAllStatus();
      [
        allStatus.sendBoxs[0].scanBoards[0].status.panels[2],
        allStatus.sendBoxs[0].scanBoards[2].status.panels[5],
        allStatus.sendBoxs[3].scanBoards[3].status.panels[4],
      ].forEach((panel) => {
        panel.details!.linkStatus.signal_s = V3proPanelStatusEnum.ERROR;
      });
      await subjectMessage(new V3proCheckPanelSignalTask(allStatus));
    } catch (e: any) {
      loggerStdout.error(e?.message || e);
    }
  }

  /**
   * 绘图
   */
  async testDrawImage() {
    const allStatus = v3proMockScreenAllStatus();
    const helper = new V3proScreenLayoutHelper(allStatus);
    helper.setPanelErrById(allStatus.sendBoxs[0].layout.outPorts[0].scanBoards[0].id, 0);
    helper.setPanelErrById(allStatus.sendBoxs[0].layout.outPorts[3].scanBoards[3].id, 0);
    const image = new V3proScreenImageHelper(helper);
    image.draw();

    await image.export2File(
      getAppDataPath("screens", createTimestampFilename("4k-draw-image", "png")),
    );
  }

  /**
   * 测试4K绘图
   */
  async test4KDrawImage() {
    loggerStdout.info("4K绘图压力测试:");
    console.time("生成坏点（二进制列表）");
    const allStatus: V3proScreenAllStatus = v3proMockScreenAllStatus();
    const binary = new V3ProBinaryPixel(3840, 2160);

    // for (let x = 0; x < 3840; x++) {
    //   for (let y = 0; y < 2160; y++) {
    //     // binary.setTrue(x, y);
    //     if ((y % 2 === 0 && x % 2 === 0) || (y % 2 === 1 && x % 2 === 1)) {
    //       binary.setTrue(x, y);
    //     }
    //   }
    // }

    V3proAllStatusLambda.accAllStatusXY(allStatus);
    const panel = allStatus.sendBoxs[1].scanBoards[1].status.panels[2];
    const { width, height } = allStatus.sendBoxs[1].scanBoards[1].status.panelConf;

    for (let x = panel.x!; x < panel.x! + width; x++) {
      for (let y = panel.y!; y < panel.y! + height; y++) {
        if (Math.random() > 0.1) binary.setTrue(x, y);
      }
    }

    const pixelCount = 3840 * 2160;
    console.log(
      "坏点数量：%s , 占比 %s %",
      binary.trueCount(),
      Math.round((binary.trueCount() / pixelCount) * 1000) / 10,
    );

    console.timeEnd("生成坏点（二进制列表）");

    console.time("标记所有坏点（同时标记所在面板、扫描版、发送盒）");
    const helper = new V3proScreenLayoutHelper(allStatus);
    helper.setPixelErrByBinary(binary);
    console.timeEnd("标记所有坏点（同时标记所在面板、扫描版、发送盒）");

    console.time("canvas绘制图片");
    const image = new V3proScreenImageHelper(helper, ["panel", "pixel"]);
    image.draw(true);
    console.timeEnd("canvas绘制图片");

    console.time("导出坏点图片");
    await image.export2File(
      getAppDataPath("screens", createTimestampFilename("4k-draw-image", "png")),
    );
    console.timeEnd("导出坏点图片");
  }

  /**
   * 发送盒信号输入故障
   */
  async testSendBoxSignalInput() {
    try {
      loggerStdout.info("信号源输入故障测试");
      const allStatus: V3proScreenAllStatus = v3proMockScreenAllStatus();
      allStatus.sendBoxs[0].status.healthDesc.description = [HealthDescEnum.INPUT_LOSE];
      allStatus.sendBoxs[0].status.health = HealthEnum.ABNORMAL;
      await subjectMessage(new V3proCheckSendboxSignalInputTask(allStatus));
    } catch (e: any) {
      loggerStdout.error(e?.message || e);
    }
  }

  __stop(): Promise<boolean> {
    return Promise.resolve(false);
  }
}
